﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Xml;

namespace Common.OpenXml
{
    /// <summary>
    /// utility to create Word document 
    /// </summary>
    public class WordWriter
    {
        #region general
        private string _FilePath;
        /// <summary></summary>
        public string FilePath
        {
            get
            {
                return this._FilePath;
            }
            set
            {
                this._FilePath = value;
            }
        }

        private string _Title;
        /// <summary></summary>
        public string Title
        {
            get
            {
                return this._Title;
            }
            set
            {
                this._Title = value;
            }
        }

        private string _Subject;
        /// <summary></summary>
        public string Subject
        {
            get
            {
                return this._Subject;
            }
            set
            {
                this._Subject = value;
            }
        }

        private string _Author;
        /// <summary></summary>
        public string Author
        {
            get
            {
                return this._Author;
            }
            set
            {
                this._Author = value;
            }
        }

        private Image _HeaderImage;
        /// <summary></summary>
        public Image HeaderImage
        {
            get
            {
                return this._HeaderImage;
            }
            set
            {
                this._HeaderImage = value;
            }
        }

        private bool _CreateTableOfContents;
        /// <summary></summary>
        public bool CreateTableOfContents
        {
            get
            {
                return this._CreateTableOfContents;
            }
            set
            {
                this._CreateTableOfContents = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath"></param>
        public WordWriter(string filePath)
        {
            this._FilePath = filePath;
            this._Title = Path.GetFileNameWithoutExtension(filePath);
            this._Subject = string.Empty;
            this._Author = Environment.UserName;
            this._HeaderImage = null;

            if(File.Exists(filePath))
                File.Delete(filePath);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="headerImg"></param>
        public WordWriter(string filePath, Image headerImg):this(filePath)
        {
            this._HeaderImage = headerImg;
        }
        #endregion

        #region add sections
        /// <summary>
        /// header image + title 
        /// </summary>
        /// <param name="includeFirstPage"></param>
        public void AddHeader(bool includeFirstPage)
        {
            if (!File.Exists(this._FilePath))
            {
                PackageHelper pkgHelper = new PackageHelper(Properties.Resources.BaseWordDocument);
                pkgHelper.Save(this._FilePath);
                pkgHelper.Dispose();
            }

            MemoryStream mStream=new MemoryStream(Encoding.Default.GetBytes(Properties.Resources.header));
            this.WDAddHeader(this._FilePath, mStream);
            mStream.Close();
        }

        private void WDAddHeader(string docName, Stream headerContent)
        {
            //  Given a document name, and a stream containing valid header content,
            //  add the stream content as a header in the document.

            const string documentRelationshipType =
                "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
            const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
            const string headerContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml";
            const string headerRelationshipType =
                "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
            const string relationshipNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";

            PackagePart documentPart = null;

            using (Package wdPackage = Package.Open(docName, FileMode.Open, FileAccess.ReadWrite))
            {
                //  Get the main document part (document.xml).
                foreach (
                    System.IO.Packaging.PackageRelationship relationship in
                        wdPackage.GetRelationshipsByType(documentRelationshipType))
                {
                    Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative),
                                                                   relationship.TargetUri);
                    documentPart = wdPackage.GetPart(documentUri);
                    //  There is only one officeDocument.
                    break;
                }

                Uri uriHeader = new Uri("/word/header1.xml", UriKind.Relative);
                if (wdPackage.PartExists(uriHeader))
                {
                    //  Although you can delete the relationship
                    //  to the existing node, the next time you save
                    //  the document after making changes, Word
                    //  will delete the relationship.
                    wdPackage.DeletePart(uriHeader);
                }
                //  Create the header part.
                PackagePart headerPart = wdPackage.CreatePart(uriHeader, headerContentType);

                //  Load the content from the input stream. 
                //  This may seem redundant, but you must read it at some point.
                //  If you ever need to analyze the contents of the header,
                //  at least it is already in an XmlDocument.
                //  This code uses the XmlDocument object only as
                //  a "pass-through" -- giving it a place to hold as 
                //  it moves from the input stream to the output stream.
                //  The code could read each byte from the input stream, and
                //  write each byte to the output stream, but this seems
                //  simpler...
                XmlDocument headerDoc = new XmlDocument();
                headerContent.Position = 0;
                headerDoc.Load(headerContent);

                //  Write the header out to its part.
                headerDoc.Save(headerPart.GetStream());

                //  Create the document's relationship to the new part.
                PackageRelationship rel = documentPart.CreateRelationship(uriHeader, TargetMode.Internal,
                                                                          headerRelationshipType);
                string relID = rel.Id;

                //  Manage namespaces to perform Xml XPath queries.
                NameTable nt = new NameTable();
                XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
                nsManager.AddNamespace("w", wordmlNamespace);

                //  Get the document part from the package.
                //  Load the XML in the part into an XmlDocument instance.
                XmlDocument xdoc = new XmlDocument(nt);
                xdoc.Load(documentPart.GetStream());

                //  Find the node containing the document layout.
                XmlNode targetNode = xdoc.SelectSingleNode("//w:sectPr", nsManager);
                if (targetNode != null)
                {
                    //  Delete any existing references to headers.
                    XmlNodeList headerNodes = targetNode.SelectNodes("./w:headerReference", nsManager);
                    foreach (System.Xml.XmlNode headerNode in headerNodes)
                    {
                        targetNode.RemoveChild(headerNode);
                    }

                    //  Create the new header reference node.
                    XmlElement node = xdoc.CreateElement("w:headerReference", wordmlNamespace);
                    XmlAttribute attr = node.Attributes.Append(xdoc.CreateAttribute("r:id", relationshipNamespace));
                    attr.Value = relID;
                    node.Attributes.Append(attr);
                    targetNode.InsertBefore(node, targetNode.FirstChild);
                }

                //  Save the document XML back to its part.
                xdoc.Save(documentPart.GetStream(FileMode.Create, FileAccess.Write));
            }
        }


        #endregion

        #region add pages

        #endregion

        #region finishing up

        #endregion
    }
}
